﻿using System;
using System.Collections.Generic;
using System.Text;
using DocumentFormat.OpenXml;
using P = DocumentFormat.OpenXml.Presentation;

namespace Fantom.Animation
{
	/// <summary>
	/// 抽象类，描述的是基动画。一个基动画代表一个具体的行为动画。
	/// </summary>
	public abstract class BaseBehavior : IAnimationBehavior
	{
		public IApplication Application { get; internal set; }

		public IFantomObject Parent { get; internal set; }

		/// <summary>
		/// 动画是否可叠加。
		/// 请和 <see cref="IsAccumulate"/> 联合使用。
		/// <para>
		/// 如果您希望您的动画允许矢量叠加，
		/// 您需要将 <see cref="IsAccumulate"/> 与 <see cref="IsAccumulate"/> 
		/// 同时设为 <see cref="true"/> 。
		/// </para>
		/// 在 Fantom 中，为了实现动画更自由的组合，该默认值为 <see cref="true"/> 。
		/// </summary>
		public bool IsAccumulate { get; set; }

		/// <summary>
		/// 动画是否允许与其他运行中的动画合并。
		/// 请和 <see cref="IsAccumulate"/> 联合使用。
		/// <para>
		/// 如果您希望您的动画允许矢量叠加，
		/// 您需要将 <see cref="IsAccumulate"/> 与 <see cref="IsAccumulate"/> 
		/// 同时设为 <see cref="true"/> 。
		/// </para>
		/// 在 Fantom 中，为了实现动画更自由的组合，该默认值为 <see cref="true"/> 。
		/// </summary>
		public bool AllowAdditive { get; set; }

		public Emu Duration { get; set; } = Emu.Seconds1 * 2;

		public Emu Delay { get; set; } = Emu.Seconds0;

		public bool AutoReverse { get; set; } = false;

		public Emu Accelerate { get; set; } = Emu.Num0;

		public Emu Decelerate { get; set; } = Emu.Num0;

		public Emu BounceEnd { get; set; } = Emu.Num0;

		public Emu RepeatCount { get; set; } = Emu.Double1;

		public bool IsRewindAtEnd { get; set; } = false;

		public IShape Shape { get; set; } = null;

		public void Delete()
		{
			(Parent as IAnimationEffect).Remove(this);
		}

		#region static

		/// <summary>
		/// 由关键字生成指定行为对象。
		/// </summary>
		internal static BaseBehavior LoadBehaviorFromKeyWord(OpenXmlElement anim, ITheme theme)
		{
			var keyWord = anim.LocalName;

			switch (keyWord)
			{
				case "set":
					return SetBehavior.LoadBehaviorFromElement(anim);
				case "anim":
					return PropertyBehavior.LoadBehaviorFromElement(anim, theme);
				case "animRot":
					return RotationBehavior.LoadBehaviorFromElement(anim);
				case "animMotion":
					return MotionBehavior.LoadBehaviorFromElement(anim);
				case "animEffect":
					return FilterBehavior.LoadBehaviorFromElement(anim);
				case "animScale":
					return ScaleBehavior.LoadBehaviorFromElement(anim);
				case "animClr":
					return ColorBehavior.LoadBehaviorFromElement(anim, theme);
				default:
					Console.BackgroundColor = ConsoleColor.Red;
					Console.WriteLine(anim.OuterXml);
					Console.ResetColor();
					throw new Exception("未知动画。");
			}
			return null;
		}

		/// <summary>
		/// 设置行为的基础属性。
		/// </summary>
		/// <param name="bhv">未初始化赋值的空行为实例。</param>
		/// <param name="element">不同行为节点。</param>
		public static void SetBehaviorFromElement(BaseBehavior bhv, OpenXmlElement element)
		{
			var xbhv = element.GetFirstChild<P.CommonBehavior>();
			var ctn = xbhv.CommonTimeNode;
			var stlst = ctn.StartConditionList;
			P.Condition cond = null;

			if (stlst != null)
				cond = stlst.GetFirstChild<P.Condition>();

			if (xbhv.Accumulate != null)
				bhv.IsAccumulate = xbhv.Accumulate.Value == P.BehaviorAccumulateValues.Always;

			if (xbhv.Additive != null)
				bhv.AllowAdditive = xbhv.Additive.Value == P.BehaviorAdditiveValues.Sum;

			if (ctn.Restart != null)
				bhv.IsRewindAtEnd = ctn.Restart.Value == P.TimeNodeRestartValues.Never;

			if (ctn.Acceleration != null)
				bhv.Accelerate = ctn.Acceleration;

			if (ctn.Deceleration != null)
				bhv.Decelerate = ctn.Deceleration;

			if (ctn.AutoReverse != null)
				bhv.AutoReverse = ctn.AutoReverse;

			if (ctn.PresetBounceEnd != null)
				bhv.BounceEnd = ctn.PresetBounceEnd;

			if (cond != null && cond.Delay != null)
				bhv.Delay = Emu.Parse(cond.Delay);

			if (ctn.Duration != null)
			{
				bhv.Duration = Emu.Parse(ctn.Duration);
			}

		}

		public override string ToString()
		{
			var sb = new StringBuilder(
				string.Format("{0, -17}, del: {1, -10}, dur: {2,-10}, shp: {3, -10}",
				GetType().Name,
				Delay,
				Duration,
				Shape.Name));
			// sb.Append(string.Format("shp: {0}", Shape.Name));
			return sb.ToString();
		}

		public static AnimatableProperty GetAnimatableProperty(OpenXmlElement element)
		{
			var xbhv = element.GetFirstChild<P.CommonBehavior>();
			var attname = xbhv.AttributeNameList.GetFirstChild<P.AttributeName>();
			switch (attname.InnerText)
			{
				case "ppt_x":
					return AnimatableProperty.X;
				case "ppt_y":
					return AnimatableProperty.Y;
				case "style.visibility":
					return AnimatableProperty.Visibility;
				case "style.color":
				case "fillcolor":
				case "stroke.color":
				case "ppt_c":
					return AnimatableProperty.Color;
				default:
					return AnimatableProperty.None;
			}

		}


		#endregion





	}
}
